package model

import (
	"context"
	"fmt"
	sq "github.com/Masterminds/squirrel"
	"github.com/zeromicro/go-zero/core/stores/cache"
	"github.com/zeromicro/go-zero/core/stores/sqlc"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"xialou_platform/app/requestx"
)

var _ AgentModel = (*customAgentModel)(nil)

type (
	// AgentModel is an interface to be customized, add more methods here,
	// and implement the added methods in customAgentModel.
	AgentModel interface {
		agentModel
		FindOneByPhone(ctx context.Context, phone string) (*Agent, error)
		FindOneByIdCard(ctx context.Context, idCard string) (*Agent, error)
		FindOneByCompany(ctx context.Context, company string) (*Agent, error)
		FindOneByUnionId(ctx context.Context, unionId string) (*Agent, error)

		FindListCount(ctx context.Context, keyword string, status int64) int64
		FindList(ctx context.Context, page *requestx.ListReq, status int64) ([]*Agent, error)

		FindListCountByParentId(ctx context.Context, parentId int64) int64
		FindListByParentId(ctx context.Context, page *requestx.ListReq, parentUid int64) ([]*Agent, error)

		FindTeamSize(ctx context.Context, Type, AgentId int64) int64
	}

	customAgentModel struct {
		*defaultAgentModel
	}
)

// NewAgentModel returns a model for the database table.
func NewAgentModel(conn sqlx.SqlConn, c cache.CacheConf) AgentModel {
	return &customAgentModel{
		defaultAgentModel: newAgentModel(conn, c),
	}
}

func (m *defaultAgentModel) FindOneByPhone(ctx context.Context, phone string) (*Agent, error) {
	publicAgentPhoneKey := fmt.Sprintf("%s%v", cachePublicAgentPhonePrefix, phone)
	var resp Agent
	err := m.QueryRowCtx(ctx, &resp, publicAgentPhoneKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
		query := fmt.Sprintf("select %s from %s where phone = $1 limit 1", agentRows, m.table)
		return conn.QueryRowCtx(ctx, v, query, phone)
	})
	switch err {
	case nil:
		return &resp, nil
	case sqlc.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (m *defaultAgentModel) FindOneByIdCard(ctx context.Context, idCard string) (*Agent, error) {
	publicAgentIdCardKey := fmt.Sprintf("%s%v", cachePublicAgentIdCardPrefix, idCard)
	var resp Agent
	err := m.QueryRowCtx(ctx, &resp, publicAgentIdCardKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
		query := fmt.Sprintf("select %s from %s where id_card = $1 limit 1", agentRows, m.table)
		return conn.QueryRowCtx(ctx, v, query, idCard)
	})
	switch err {
	case nil:
		return &resp, nil
	case sqlc.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (m *defaultAgentModel) FindOneByCompany(ctx context.Context, company string) (*Agent, error) {
	publicAgentCompanyKey := fmt.Sprintf("%s%v", cachePublicAgentCompanyPrefix, company)
	var resp Agent
	err := m.QueryRowCtx(ctx, &resp, publicAgentCompanyKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
		query := fmt.Sprintf("select %s from %s where company = $1 limit 1", agentRows, m.table)
		return conn.QueryRowCtx(ctx, v, query, company)
	})
	switch err {
	case nil:
		return &resp, nil
	case sqlc.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (m *defaultAgentModel) FindOneByUnionId(ctx context.Context, unionId string) (*Agent, error) {
	publicAgentUnionIdKey := fmt.Sprintf("%s%v", cachePublicAgentUnionIdPrefix, unionId)
	var resp Agent
	err := m.QueryRowCtx(ctx, &resp, publicAgentUnionIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
		query := fmt.Sprintf("select %s from %s where union_id = $1 limit 1", agentRows, m.table)
		return conn.QueryRowCtx(ctx, v, query, unionId)
	})
	switch err {
	case nil:
		return &resp, nil
	case sqlc.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (m *defaultAgentModel) FindListCount(ctx context.Context, keyword string, status int64) int64 {
	selectBuilder := sq.Select("count(1)").From(m.table)
	if len(keyword) != 0 {
		selectBuilder = selectBuilder.Where(sq.Like{"phone": fmt.Sprint("%", keyword, "%")})
	}
	if status > -1 {
		selectBuilder = selectBuilder.Where(sq.Eq{"status": status})
	}

	query, args, err := selectBuilder.PlaceholderFormat(sq.Dollar).ToSql()
	if err != nil {
		return 0
	}
	var count int64
	err = m.QueryRowNoCacheCtx(ctx, &count, query, args...)
	if err != nil {
		return 0
	}
	return count

}

func (m *defaultAgentModel) FindList(ctx context.Context, page *requestx.ListReq, status int64) ([]*Agent, error) {
	selectBuilder := sq.Select(agentRows).From(m.table).Limit(page.Limit()).Offset(page.Offset())
	if len(page.Keyword) != 0 {
		selectBuilder = selectBuilder.Where(sq.Like{"phone": fmt.Sprint("%", page.Keyword, "%")})
	}
	if status > -1 {
		selectBuilder = selectBuilder.Where(sq.Eq{"status": status})
	}
	query, args, err := selectBuilder.OrderBy("create_time desc").PlaceholderFormat(sq.Dollar).ToSql()
	if err != nil {
		return nil, err
	}
	var resp []*Agent
	err = m.QueryRowsNoCacheCtx(ctx, &resp, query, args...)
	return resp, err
}

func (m *defaultAgentModel) FindListCountByParentId(ctx context.Context, parentId int64) int64 {
	selectBuilder := sq.Select("count(1)").From(m.table).Where(sq.Eq{"parent_uid": parentId})

	query, args, err := selectBuilder.PlaceholderFormat(sq.Dollar).ToSql()
	if err != nil {
		return 0
	}
	var count int64
	err = m.QueryRowNoCacheCtx(ctx, &count, query, args...)
	if err != nil {
		return 0
	}
	return count

}

func (m *defaultAgentModel) FindListByParentId(ctx context.Context, page *requestx.ListReq, parentId int64) ([]*Agent, error) {
	selectBuilder := sq.Select(agentRows).From(m.table).Limit(page.Limit()).Offset(page.Offset()).Where(sq.Eq{"parent_uid": parentId})
	query, args, err := selectBuilder.OrderBy("create_time desc").PlaceholderFormat(sq.Dollar).ToSql()
	if err != nil {
		return nil, err
	}
	var resp []*Agent
	err = m.QueryRowsNoCacheCtx(ctx, &resp, query, args...)
	return resp, err
}
func (m *defaultAgentModel) FindTeamSize(ctx context.Context, Type, AgentId int64) int64 {
	selectBuilder := sq.Select("count(1)").From(m.table)

	switch Type {
	case 3:
		selectBuilder = selectBuilder.Where(sq.Eq{"top_uid": AgentId})
	default:
		selectBuilder = selectBuilder.Where(sq.Eq{"parent_uid": AgentId})
	}
	query, args, err := selectBuilder.PlaceholderFormat(sq.Dollar).ToSql()
	if err != nil {
		return 0
	}
	var count int64
	err = m.QueryRowNoCacheCtx(ctx, &count, query, args...)
	if err != nil {
		return 0
	}
	return count

}
